#include <Ape/Object.h>

#include <malloc.h>

#include <Ape/String.h>
#include <Ape/EMemoryCorruption.h>
#include <Ape/EventModel/Callback.h>
#include <Ape/MT/Mutex.h>

namespace Ape {
	/*
	Object::Object()
		: m_RefCount(0u),
		  m_Callable(true),
		  m_Callbacks(NULL)
	{
		m_Callbacks = reinterpret_cast<void*>(new Collections::Queue<EventModel::Callback*>);
	}
	*/
	
	struct CallbackJoint {
		EventModel::Callback* Callback;
		CallbackJoint* Next;
		
		static CallbackJoint* Create() {
			CallbackJoint* j = new CallbackJoint;
			j->Callback = NULL;
			j->Next = NULL;
			return j;
		}
	};
	
	Object::Object()
			: m_RefCount (0u),
			m_Callbacks (NULL),
			m_Mutex (NULL)
	{
		initCallbacksQueue();
	}
	
	void Object::initCallbacksQueue() {
	
	}
	void Object::destroyCallbacksQueue() {
		CallbackJoint* j = m_Callbacks;
		while (j) {
			CallbackJoint* toDelete = j;
			j = j->Next;
			if (toDelete->Callback)
				toDelete->Callback->Neutralize(); // callback kills itself with its own hands
			delete toDelete;
		}
	}
	void Object::__AppendCallback (EventModel::Callback* callback) const {
		CallbackJoint* j = CallbackJoint::Create();
		j->Callback = callback;
		j->Next = m_Callbacks;
		m_Callbacks = j;
	}
	
	
	Object::Object (const Object& other)
			: m_RefCount (0u),
			m_Callbacks (NULL),
			m_Mutex (NULL)
	{
		initCallbacksQueue();
		if (other.m_Mutex)
			InitObjectMutex();
	}
	
	Object::~Object() {
		if (m_RefCount)
			throw EMemoryCorruption (L"Object is being deleted though there are still references on it. (Soon the smart pointers will try to delete this piece of memory too - nothing will be OK =( )");
			
		destroyCallbacksQueue();
		DestroyObjectMutex();
	}
	
	void Object::_Dump (bool /*verbose*/) const {
		printf ("Object dump for `%s' at [%p]" _R_NEWLINE, getVTypeName(), (void*) this);
		DUMP_NON_V_TYPE;
	}
	
	const String Object::ToString() const {
		return getVTypeName();
	}
	
	
	size_t Object::__AddRef() const {
		return ++m_RefCount;
	}
	size_t Object::__RemRef() const {
		if (!m_RefCount)
			throw EMemoryCorruption (L"Object is being derefferenced though there already aren't any references on it. Something really strange is going on. (May be a smart pointer has been deleted but it's destructor hasn't been called)");
		return --m_RefCount;
	}
	size_t Object::__GetRef() const {
		return m_RefCount;
	}
	
	void Object::InitObjectMutex() {
		m_Mutex = new MT::Mutex ("Ape::Object root-mutex");
	}
	void Object::DestroyObjectMutex() {
		del (m_Mutex)
	}
	MT::Mutex& Object::GetObjectMutex() const {
		return *m_Mutex;
	}
}


